package org.jfunction.ui.internal.editor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
import org.eclipse.ui.texteditor.spelling.SpellingAnnotation;
import org.eclipse.ui.texteditor.spelling.SpellingProblem;

public class JFunctionSpellingProblemCollector implements ISpellingProblemCollector{

	/** Annotation model. */
	private IAnnotationModel fAnnotationModel;

	/** Annotations to add. */
	private Map fAddAnnotations;
	
	/** Lock object for modifying the annotations. */
	private Object fLockObject;

	private IDocument document;

	private String[] partitions;

	private String partitioning;

	/**
	 * Initializes this collector with the given annotation model.
	 *
	 * @param annotationModel the annotation model
	 */
	public JFunctionSpellingProblemCollector(IAnnotationModel annotationModel, IDocument document, String partitioning, String[] partitions) {
		Assert.isLegal(annotationModel != null);
		this.document = document;
		this.partitions = partitions;
		this.partitioning = partitioning;
		fAnnotationModel= annotationModel;
		if (fAnnotationModel instanceof ISynchronizable)
			fLockObject= ((ISynchronizable)fAnnotationModel).getLockObject();
		else
			fLockObject= fAnnotationModel;
	}

	/*
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept(org.eclipse.ui.texteditor.spelling.SpellingProblem)
	 */
	public void accept(SpellingProblem problem) {
		try {
			
			IDocumentExtension3 ext = (IDocumentExtension3)document;
			String contentType = ext.getContentType(partitioning, problem.getOffset(), true);
			
			for (String partition : partitions) {
				if (partition.equals(contentType))
					fAddAnnotations.put(new SpellingAnnotation(problem), new Position(problem.getOffset(), problem.getLength()));
			}
		} catch (BadLocationException e) {
			// silent
		} catch (BadPartitioningException e) {
			// silent
		}
	}

	/*
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#beginCollecting()
	 */
	public void beginCollecting() {
		fAddAnnotations= new HashMap();
	}

	/*
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#endCollecting()
	 */
	public void endCollecting() {
		
		List toRemove= new ArrayList();
		
		synchronized (fLockObject) {
			Iterator iter= fAnnotationModel.getAnnotationIterator();
			while (iter.hasNext()) {
				Annotation annotation= (Annotation)iter.next();
				if (SpellingAnnotation.TYPE.equals(annotation.getType()))
					toRemove.add(annotation);
			}
			Annotation[] annotationsToRemove= (Annotation[])toRemove.toArray(new Annotation[toRemove.size()]);

			if (fAnnotationModel instanceof IAnnotationModelExtension)
				((IAnnotationModelExtension)fAnnotationModel).replaceAnnotations(annotationsToRemove, fAddAnnotations);
			else {
				for (int i= 0; i < annotationsToRemove.length; i++)
					fAnnotationModel.removeAnnotation(annotationsToRemove[i]);
				for (iter= fAddAnnotations.keySet().iterator(); iter.hasNext();) {
					Annotation annotation= (Annotation)iter.next();
					fAnnotationModel.addAnnotation(annotation, (Position)fAddAnnotations.get(annotation));
				}
			}
		}

		fAddAnnotations= null;
	}

}
